package database;

/** Checks that all the jar-libraries needed exist.
 * <br>
 * Copyright (C) 2014 I.Puigdomenech.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses/
 * 
 * @author Ignasi Puigdomenech */
public class Main {
  private static final String progName = "Program \"DataBase\""; //Leta? Lagra? Samla?
  /** New-line character(s) to substitute "\n" */
  private static final String nl = System.getProperty("line.separator");
  private static boolean started = false;
  private static final String SLASH = java.io.File.separator;

  /** Check that all the jar-libraries needed do exist.
   * @param args the command line arguments */
  public static void main(String[] args) {
    // ---- are all jar files needed there?
    if(!doJarFilesExist()) {return;}

    // ---- ok!
    FrameDBmain.main(args);

  } //main

//<editor-fold defaultstate="collapsed" desc="doJarFilesExist">
/** Look in the running jar file's classPath Manifest for any other "library"
 * jar-files listed under "Class-path".
 * If any of these jar files does not exist display an error message
 * (and an error Frame) and continue.
 * @return true if all needed jar files exist; false otherwise.
 * @version 2014-Jan-17 */
  public static boolean doJarFilesExist() {
    java.io.File libJarFile;
    java.util.jar.JarFile runningJar = getRunningJarFile();
    // runningJar.getName() = C:\Eq-Calc_Java\dist\Prog.jar
    if(runningJar != null) { // if running within Netbeans there will be no jar-file
        java.util.jar.Manifest manifest;
        try {manifest = runningJar.getManifest();}
        catch (java.io.IOException ex) {
            manifest = null;
            String msg = "Warning: no manifest found in the application's jar file:"+nl+
                    "\""+runningJar.getName()+"\"";
            ErrMsgBx emb = new ErrMsgBx(msg, progName);
            //this will return true;
        }
        if(manifest != null) {
            String classPath = manifest.getMainAttributes().getValue("Class-Path");
            if(classPath != null && classPath.length() > 0) {
                // this will be a list of space-separated names
                String[] jars = classPath.split("\\s+"); //regular expression to match one or more spaces
                if(jars.length >0) {
                    java.io.File[] rootNames = java.io.File.listRoots();
                    boolean isPathAbsolute;
                    for(String jar : jars) {
                        isPathAbsolute = false;
                        for(java.io.File f : rootNames) {
                            if(jar.toLowerCase().startsWith(f.getAbsolutePath().toLowerCase())) {
                                isPathAbsolute = true;
                                break;}
                        }
                        if(!isPathAbsolute) {
                            // add the application's path
                            String p = getPathApp();
                            if(!p.endsWith(SLASH) && !jar.startsWith(SLASH)) {p = p+SLASH;}
                            jar = p + jar;
                        }
                        libJarFile = new java.io.File(jar);
                        if(libJarFile.exists()) {continue;}
                        libJarFile = new java.io.File(libJarFile.getAbsolutePath());
                        ErrMsgBx emb = new ErrMsgBx(progName+" - Error:"+nl+
                                "   File: \""+libJarFile.getName()+"\"  not found in:"+nl+
                                "   \""+libJarFile.getParent()+"\"", progName);
                        return false;
                    }
                }
            }//if classPath != null
        } //if Manifest != null
    } //if runningJar != null
    return true;
  } //doJarFilesExist()

//<editor-fold defaultstate="collapsed" desc="getRunningJarFile()">
/** Find out the jar file that contains this class
 * @return a File object of the jar file containing the enclosing class "Main",
 * or null if the main class is not inside a jar file.
 * @version 2014-Jan-17 */
public static java.util.jar.JarFile getRunningJarFile() {
  //from http://www.rgagnon.com/javadetails/
  //and the JarClassLoader class
  C c = new C();
  String className = c.getClass().getName().replace('.', '/');
  // class = "progPackage.Main";   className = "progPackage/Main"
  java.net.URL url = c.getClass().getResource("/" + className + ".class");
  // url = "jar:file:/C:/Eq-Calc_Java/dist/Prog.jar!/progPackage/Main.class"
  if(url.toString().startsWith("jar:")) {
      java.net.JarURLConnection jUrlC;
      try{
        jUrlC = (java.net.JarURLConnection)url.openConnection();
        return jUrlC.getJarFile();
      } catch(java.io.IOException ex) {
        ErrMsgBx emb = new ErrMsgBx("Error "+ex.toString(), progName);
        return null;
      }
  } else {
        // it might not be a jar file if running within NetBeans
      return null;
  }
} //getRunningJarFile()
//</editor-fold>

//</editor-fold>

//<editor-fold defaultstate="collapsed" desc="getPathApp">
/** Get the path where an application is located.
 * @return the directory where the application is located,
 * or "user.dir" if an error occurs
 * @version 2014-Jan-17 */
  private static class C {private static void C(){}}
  public static String getPathApp() {
    C c = new C();
    String path;
    java.net.URI dir;
    try{
        dir = c.getClass().
                getProtectionDomain().
                    getCodeSource().
                        getLocation().
                            toURI();
        if(dir != null) {
            String d = dir.toString();
            if(d.startsWith("jar:") && d.endsWith("!/")) {
                d = d.substring(4, d.length()-2);
                dir = new java.net.URI(d);
            }
            path = (new java.io.File(dir.getPath())).getParent();
        } else {path = System.getProperty("user.dir");}
    }
    catch (java.net.URISyntaxException e) {
      if(!started) {
        ErrMsgBx emb = new ErrMsgBx("Error: "+e.toString()+nl+
                    "   trying to get the application's directory.", progName);
      }
      path = System.getProperty("user.dir");
    } // catch
    started = true;
    return path;
  } //getPathApp()
//</editor-fold>

//<editor-fold defaultstate="collapsed" desc="ErrMsgBx">
  /** Displays a "message box" modal dialog with an "OK" button.<br>
   * Why is this needed? For any java console application: if started using
   * javaw.exe (on Windows) or through a ProcessBuilder, no console will appear.
   * Error messages are then "lost" unless a log-file is generated and the user
   * reads it. This class allows the program to stop running and wait for the user
   * to confirm that the error message has been read.
   * <br>
   * A small frame (window) is first created and made visible. This frame is
   * the parent to the modal "message box" dialog, and it has an icon on the
   * task bar (Windows).  Then the modal dialog is displayed on top of the
   * small parent frame.
   * <br>
   * Copyright (C) 2014  I.Puigdomenech.
   * @author Ignasi Puigdomenech
   * @version 2014-Jan-30 */
  static class ErrMsgBx {

  /** Displays a "message box" modal dialog with an "OK" button and a title.
   * The message is displayed in a text area (non-editable),
   * which can be copied and pasted elsewhere.
   * @param msg will be displayed in a text area, and line breaks may be
   * included, for example: <code>new MsgBox("Very\nbad!",""); </code>
   * If null or empty nothing is done.
   * @param title for the dialog. If null or empty, "Error:" is used
   * @version 2014-Jan-30 */
  public ErrMsgBx(String msg, String title) {
    if(msg == null || msg.trim().length() <=0) {
        System.err.println("--- MsgBox: null or empty \"message\".");
        return;
    }
    //--- Title
    if(title == null || title.length() <=0) {title = " Error:";}
    java.awt.Frame frame = new java.awt.Frame(title);
    //--- Icon
    String iconName = "images/ErrMsgBx.gif";
    java.net.URL imgURL = this.getClass().getResource(iconName);
    if(imgURL != null) {frame.setIconImage(new javax.swing.ImageIcon(imgURL).getImage());}
    else {System.err.println("--- Error in MsgBox constructor: Could not load image = \""+iconName+"\"");}
    frame.pack();
    //--- centre Window frame on Screen
    java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
    int left; int top;
    left = Math.max(55, (screenSize.width  - frame.getWidth() ) / 2);
    top = Math.max(10, (screenSize.height - frame.getHeight()) / 2);
    frame.setLocation(Math.min(screenSize.width-100, left), Math.min(screenSize.height-100, top));
    //---
    final String msgText = msg.trim();
    System.out.println("--- MsgBox:"+nl+msgText+nl+"---");
    frame.setVisible(true);
    //javax.swing.JOptionPane.showMessageDialog(frame, msg, title, javax.swing.JOptionPane.ERROR_MESSAGE);
    MsgBoxDialog msgBox = new MsgBoxDialog(frame, msgText, title, true);
    msgBox.setVisible(true); // becase the dialog is modal, statements below will wait
    msgBox.dispose();
    frame.setVisible(false);
    frame.dispose();
  }

  //<editor-fold defaultstate="collapsed" desc="MsgBoxDialog">
  private static class MsgBoxDialog extends java.awt.Dialog {
    private java.awt.Button ok;
    private java.awt.Panel p;
    private final java.awt.TextArea text;

    /**  Creates new form NewDialog */
    public MsgBoxDialog(java.awt.Frame parent, String msg, String title, boolean modal) {
        super(parent, (" "+title), modal);
        addWindowListener(new java.awt.event.WindowAdapter() {
            @Override public void windowClosing(java.awt.event.WindowEvent evt) {
                MsgBoxDialog.this.setVisible(false);
            }
        });
        setLayout(new java.awt.BorderLayout());
        p = new java.awt.Panel();
        p.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER));
        ok = new java.awt.Button();

        // find out the size of the message (width and height)
        final int wMax = 85; final int hMax=20;
        final int wMin = 5; final int hMin = 1;
        int w = wMin;
        int h=hMin; int i=0; int j=wMin;
        final String eol = "\n";  char c;
        final String nl = System.getProperty("line.separator");
        while (true) {
            c = msg.charAt(i);
            String s = String.valueOf(c);
            if(s.equals(eol) || s.equals(nl)) {
                h++; j=wMin;
            } else {
                j++; w = Math.max(j,w);
            }
            i++;
            if(i >= msg.length()-1) {break;}
        }

        // create a text area
        int scroll = java.awt.TextArea.SCROLLBARS_NONE;
        if(w > wMax && h <= hMax) {scroll = scroll & java.awt.TextArea.SCROLLBARS_HORIZONTAL_ONLY;}
        if(h > hMax && w <= wMax) {scroll = scroll & java.awt.TextArea.SCROLLBARS_VERTICAL_ONLY;}
        if(w > wMax && h > hMax) {scroll = java.awt.TextArea.SCROLLBARS_BOTH;}
        w = Math.min(Math.max(w,10),wMax);
        h = Math.min(h,hMax);
        text = new java.awt.TextArea(msg, h, w, scroll);
        text.setEditable(false);
        //text.setBackground(java.awt.Color.white);
        text.addKeyListener(new java.awt.event.KeyAdapter() {
            @Override public void keyPressed(java.awt.event.KeyEvent evt) {
                if(evt.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER
                    || evt.getKeyCode() == java.awt.event.KeyEvent.VK_ESCAPE) {closeDialog();}
                if(evt.getKeyCode() == java.awt.event.KeyEvent.VK_TAB) {ok.requestFocusInWindow();}
            }
        });

        add(text, java.awt.BorderLayout.CENTER);

        ok.setLabel("OK");
        ok.addActionListener(new java.awt.event.ActionListener() {
            @Override public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeDialog();
            }
        });
        ok.addKeyListener(new java.awt.event.KeyAdapter() {
            @Override
            public void keyPressed(java.awt.event.KeyEvent evt) {
                if(evt.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER
                        || evt.getKeyCode() == java.awt.event.KeyEvent.VK_ESCAPE) {closeDialog();}
            }
        });
        p.add(ok);

        add(p, java.awt.BorderLayout.SOUTH);

        pack();

        setLocation(parent.getLocation());
        ok.requestFocusInWindow();
    }

    private void closeDialog() {this.setVisible(false);}

  } // private static class MsgBoxDialog
  //</editor-fold>
}  // static class ErrMsgBx
  //</editor-fold>

}
